package com.hifar.sso.util;

import com.hifar.sso.model.SSOUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 * 
 * @author system
 * @since 1.0.0
 */
public class JWTUtil {
    
    private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class);
    
    // JWT密钥 - 生产环境应该从配置文件读取
    private static final String SECRET = "sso-jwt-secret-key-2024";
    
    // 令牌过期时间（秒）
    private static final long EXPIRATION_TIME = 24 * 60 * 60; // 24小时
    
    /**
     * 生成JWT令牌
     * 
     * @param user 用户信息
     * @return JWT令牌
     */
    public static String generateToken(SSOUser user) {
        try {
            if (user == null || !StringUtils.hasText(user.getUserId())) {
                throw new IllegalArgumentException("用户信息不能为空");
            }
            
            Map<String, Object> claims = new HashMap<>();
            claims.put("userId", user.getUserId());
            claims.put("username", user.getUsername());
            claims.put("realName", user.getRealName());
            claims.put("email", user.getEmail());
            claims.put("phone", user.getPhone());
            claims.put("departmentId", user.getDepartmentId());
            claims.put("departmentName", user.getDepartmentName());
            claims.put("tenantId", user.getTenantId());
            claims.put("tenantName", user.getTenantName());
            claims.put("status", user.getStatus());
            
            return createToken(claims, user.getUserId());
        } catch (Exception e) {
            logger.error("生成JWT令牌异常", e);
            throw new RuntimeException("生成令牌失败", e);
        }
    }
    
    /**
     * 创建JWT令牌
     */
    private static String createToken(Map<String, Object> claims, String subject) {
        Date now = new Date();
        Date expiration = new Date(now.getTime() + EXPIRATION_TIME * 1000);
        
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(now)
                .setExpiration(expiration)
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
    }
    
    /**
     * 从令牌中获取用户ID
     * 
     * @param token JWT令牌
     * @return 用户ID
     */
    public static String getUserIdFromToken(String token) {
        try {
            if (!StringUtils.hasText(token)) {
                return null;
            }
            
            Claims claims = getClaimsFromToken(token);
            if (claims == null) {
                return null;
            }
            
            return claims.getSubject();
        } catch (Exception e) {
            logger.error("从令牌获取用户ID异常", e);
            return null;
        }
    }
    
    /**
     * 从令牌中获取用户名
     * 
     * @param token JWT令牌
     * @return 用户名
     */
    public static String getUsernameFromToken(String token) {
        try {
            if (!StringUtils.hasText(token)) {
                return null;
            }
            
            Claims claims = getClaimsFromToken(token);
            if (claims == null) {
                return null;
            }
            
            return claims.get("username", String.class);
        } catch (Exception e) {
            logger.error("从令牌获取用户名异常", e);
            return null;
        }
    }
    
    /**
     * 从令牌中获取用户信息
     * 
     * @param token JWT令牌
     * @return 用户信息
     */
    public static SSOUser getUserFromToken(String token) {
        try {
            if (!StringUtils.hasText(token)) {
                return null;
            }
            
            Claims claims = getClaimsFromToken(token);
            if (claims == null) {
                return null;
            }
            
            SSOUser user = new SSOUser();
            user.setUserId(claims.getSubject());
            user.setUsername(claims.get("username", String.class));
            user.setRealName(claims.get("realName", String.class));
            user.setEmail(claims.get("email", String.class));
            user.setPhone(claims.get("phone", String.class));
            user.setDepartmentId(claims.get("departmentId", String.class));
            user.setDepartmentName(claims.get("departmentName", String.class));
            user.setTenantId(claims.get("tenantId", String.class));
            user.setTenantName(claims.get("tenantName", String.class));
            user.setStatus(claims.get("status", Integer.class));
            
            return user;
        } catch (Exception e) {
            logger.error("从令牌获取用户信息异常", e);
            return null;
        }
    }
    
    /**
     * 验证令牌是否有效
     * 
     * @param token JWT令牌
     * @return 是否有效
     */
    public static boolean validateToken(String token) {
        try {
            if (!StringUtils.hasText(token)) {
                return false;
            }
            
            Claims claims = getClaimsFromToken(token);
            if (claims == null) {
                return false;
            }
            
            // 检查是否过期
            return !isTokenExpired(claims);
        } catch (Exception e) {
            logger.error("验证令牌异常", e);
            return false;
        }
    }
    
    /**
     * 检查令牌是否过期
     * 
     * @param token JWT令牌
     * @return 是否过期
     */
    public static boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            if (claims == null) {
                return true;
            }
            
            return isTokenExpired(claims);
        } catch (Exception e) {
            logger.error("检查令牌过期异常", e);
            return true;
        }
    }
    
    /**
     * 从令牌中获取Claims
     */
    private static Claims getClaimsFromToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            logger.debug("解析JWT令牌失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 检查Claims是否过期
     */
    private static boolean isTokenExpired(Claims claims) {
        Date expiration = claims.getExpiration();
        return expiration.before(new Date());
    }
    
    /**
     * 获取令牌过期时间
     * 
     * @param token JWT令牌
     * @return 过期时间
     */
    public static Date getExpirationDateFromToken(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            if (claims == null) {
                return null;
            }
            
            return claims.getExpiration();
        } catch (Exception e) {
            logger.error("获取令牌过期时间异常", e);
            return null;
        }
    }
    
    /**
     * 获取令牌剩余有效时间（秒）
     * 
     * @param token JWT令牌
     * @return 剩余时间（秒）
     */
    public static long getRemainingTime(String token) {
        try {
            Date expiration = getExpirationDateFromToken(token);
            if (expiration == null) {
                return 0;
            }
            
            long remaining = (expiration.getTime() - System.currentTimeMillis()) / 1000;
            return Math.max(0, remaining);
        } catch (Exception e) {
            logger.error("获取令牌剩余时间异常", e);
            return 0;
        }
    }
}